package org.example.springboot.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import jakarta.annotation.Resource;
import org.example.springboot.DTO.RecommendationDTO;
import org.example.springboot.entity.Book;
import org.example.springboot.entity.BorrowRecord;
import org.example.springboot.entity.Collection;
import org.example.springboot.entity.Rating;
import org.example.springboot.entity.User;
import org.example.springboot.enumClass.RecommendationType;
import org.example.springboot.exception.ServiceException;
import org.example.springboot.mapper.BookMapper;
import org.example.springboot.mapper.BorrowRecordMapper;
import org.example.springboot.mapper.CollectionMapper;
import org.example.springboot.mapper.RatingMapper;
import org.example.springboot.mapper.UserMapper;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 图书推荐服务类 - 重构版
 * 采用多种推荐算法，不使用推荐表存储推荐结果
 */
@Service
public class RecommendationService {
    @Resource
    private BookMapper bookMapper;
    
    @Resource
    private UserMapper userMapper;
    
    @Resource
    private RatingMapper ratingMapper;
    
    @Resource
    private CollectionMapper collectionMapper;
    
    @Resource
    private BorrowRecordMapper borrowRecordMapper;
    

    
    /**
     * 检查用户是否存在
     */
    private User checkUserExists(Long userId) {
        User user = userMapper.selectById(userId);
        if (user == null) {
            throw new ServiceException("用户不存在");
        }
        return user;
    }
    
    /**
     * 获取用户已交互过的图书ID集合
     */
    private Set<Long> getUserInteractedBookIds(Long userId) {
        // 1. 获取用户评分过的图书
        List<Rating> ratings = ratingMapper.selectList(
            new LambdaQueryWrapper<Rating>()
                .eq(Rating::getUserId, userId)
        );
        
        // 2. 获取用户收藏的图书
        List<Collection> collections = collectionMapper.selectList(
            new LambdaQueryWrapper<Collection>()
                .eq(Collection::getUserId, userId)
        );
        
        // 3. 获取用户借阅过的图书
        List<BorrowRecord> borrows = borrowRecordMapper.selectList(
            new LambdaQueryWrapper<BorrowRecord>()
                .eq(BorrowRecord::getUserId, userId)
        );
        
        // 合并所有已交互的图书ID
        Set<Long> interactedBookIds = new HashSet<>();
        
        interactedBookIds.addAll(
            ratings.stream().map(Rating::getBookId).collect(Collectors.toSet())
        );
        
        interactedBookIds.addAll(
            collections.stream().map(Collection::getBookId).collect(Collectors.toSet())
        );
        
        interactedBookIds.addAll(
            borrows.stream().map(BorrowRecord::getBookId).collect(Collectors.toSet())
        );
        
        return interactedBookIds;
    }
    
    /**
     * 获取图书详情并构建推荐DTO
     */
    private List<RecommendationDTO> buildRecommendationDTOs(
            Map<Long, Double> bookScores, 
            int limit, 
            int recommendationType) {
        
        if (bookScores.isEmpty()) {
            return Collections.emptyList();
        }
        
        // 按分数排序
        List<Map.Entry<Long, Double>> sortedEntries = bookScores.entrySet().stream()
                .sorted(Map.Entry.<Long, Double>comparingByValue().reversed())
                .limit(limit)
                .collect(Collectors.toList());
        
        // 获取图书详情
        List<Long> bookIds = sortedEntries.stream()
                .map(Map.Entry::getKey)
                .collect(Collectors.toList());
        
        if (bookIds.isEmpty()) {
            return Collections.emptyList();
        }
        
        List<Book> books = bookMapper.selectList(
            new LambdaQueryWrapper<Book>()
                .in(Book::getId, bookIds)
        );
        
        Map<Long, Book> bookMap = books.stream()
                .collect(Collectors.toMap(Book::getId, book -> book));
        
        // 构建推荐DTO
        List<RecommendationDTO> recommendations = new ArrayList<>();
        
        for (Map.Entry<Long, Double> entry : sortedEntries) {
            Long bookId = entry.getKey();
            Double score = entry.getValue();
            
            Book book = bookMap.get(bookId);
            if (book != null) {
                RecommendationDTO dto = new RecommendationDTO();
                dto.setBookId(bookId);
                dto.setTitle(book.getTitle());
                dto.setAuthor(book.getAuthor());
                dto.setCoverUrl(book.getCoverUrl());
                dto.setAvgScore(book.getAvgScore());
                dto.setRecommendationScore(new BigDecimal(score).setScale(4, RoundingMode.HALF_UP));
                dto.setRecommendationType(recommendationType);
                dto.setRecommendationTypeDesc(RecommendationType.getDescByValue(recommendationType));
                
                recommendations.add(dto);
            }
        }
        
        return recommendations;
    }
    

    

    
    /**
     * 查找相似用户
     * 此方法是协同过滤算法的一部分，实际实现可能更复杂
     * @param userId 用户ID
     * @return 相似用户ID及相似度
     */
    private Map<Long, Double> findSimilarUsers(Long userId) {
        // 实际项目中，这里应该实现用户相似度计算算法
        // 此处仅为示例，返回一个模拟的相似用户列表
        Map<Long, Double> similarUsers = new HashMap<>();
        
        // 获取所有用户
        List<User> allUsers = userMapper.selectList(
            new LambdaQueryWrapper<User>()
                .ne(User::getId, userId)
        );
        
        // 模拟计算相似度
        for (User user : allUsers) {
            // 实际应该基于用户行为计算相似度
            // 此处随机生成一个0.1到0.9的相似度
            double similarity = 0.1 + Math.random() * 0.8;
            similarUsers.put(user.getId(), similarity);
        }
        
        return similarUsers;
    }
    

   
    /**
     * 获取用户的评分数据
     */
    private Map<Long, Map<Long, Integer>> getUserRatings() {
        // 获取所有评分数据
        List<Rating> allRatings = ratingMapper.selectList(null);
        
        // 构建用户-图书-评分的映射
        Map<Long, Map<Long, Integer>> userRatings = new HashMap<>();
        
        for (Rating rating : allRatings) {
            userRatings.computeIfAbsent(rating.getUserId(), k -> new HashMap<>())
                    .put(rating.getBookId(), rating.getScore());
        }
        
        return userRatings;
    }
    
    /**
     * 计算用户相似度（基于余弦相似度）
     */
    private double calculateUserSimilarity(Map<Long, Integer> userRatings1, Map<Long, Integer> userRatings2) {
        // 找出两个用户共同评分的图书
        Set<Long> commonBooks = new HashSet<>(userRatings1.keySet());
        commonBooks.retainAll(userRatings2.keySet());
        
        if (commonBooks.isEmpty()) {
            return 0.0;
        }
        
        // 计算评分向量的点积
        double dotProduct = 0.0;
        double norm1 = 0.0;
        double norm2 = 0.0;
        
        for (Long bookId : commonBooks) {
            int rating1 = userRatings1.get(bookId);
            int rating2 = userRatings2.get(bookId);
            
            dotProduct += rating1 * rating2;
            norm1 += Math.pow(rating1, 2);
            norm2 += Math.pow(rating2, 2);
        }
        
        // 计算余弦相似度
        if (norm1 == 0.0 || norm2 == 0.0) {
            return 0.0;
        }
        
        return dotProduct / (Math.sqrt(norm1) * Math.sqrt(norm2));
    }
    
    /**
     * 获取基于用户协同过滤的推荐
     */
    public List<RecommendationDTO> getUserCFRecommendations(Long userId, Integer limit) {
        // 检查用户是否存在
        checkUserExists(userId);
        
        // 获取用户已交互的图书
        Set<Long> interactedBookIds = getUserInteractedBookIds(userId);
        
        // 获取所有用户的评分数据
        Map<Long, Map<Long, Integer>> userRatings = getUserRatings();
        
        // 目标用户的评分数据
        Map<Long, Integer> targetUserRatings = userRatings.getOrDefault(userId, new HashMap<>());
        
        // 如果用户没有评分数据，返回空列表
        if (targetUserRatings.isEmpty()) {
            return Collections.emptyList();
        }
        
        // 计算用户相似度
        Map<Long, Double> userSimilarities = new HashMap<>();
        
        for (Map.Entry<Long, Map<Long, Integer>> entry : userRatings.entrySet()) {
            Long otherUserId = entry.getKey();
            Map<Long, Integer> otherUserRatings = entry.getValue();
            
            // 跳过自己
            if (otherUserId.equals(userId)) {
                continue;
            }
            
            // 计算相似度
            double similarity = calculateUserSimilarity(targetUserRatings, otherUserRatings);
            
            // 只考虑相似度大于0的用户
            if (similarity > 0) {
                userSimilarities.put(otherUserId, similarity);
            }
        }
        
        // 获取前K个最相似的用户
        List<Map.Entry<Long, Double>> similarUsers = userSimilarities.entrySet().stream()
                .sorted(Map.Entry.<Long, Double>comparingByValue().reversed())
                .limit(20) // Top K similar users
                .collect(Collectors.toList());
        
        // 计算推荐分数
        Map<Long, Double> bookScores = new HashMap<>();
        
        for (Map.Entry<Long, Double> entry : similarUsers) {
            Long similarUserId = entry.getKey();
            Double similarity = entry.getValue();
            
            Map<Long, Integer> similarUserRatings = userRatings.get(similarUserId);
            
            // 遍历相似用户评分过的图书
            for (Map.Entry<Long, Integer> ratingEntry : similarUserRatings.entrySet()) {
                Long bookId = ratingEntry.getKey();
                Integer rating = ratingEntry.getValue();
                
                // 跳过用户已交互过的图书
                if (interactedBookIds.contains(bookId)) {
                    continue;
                }
                
                // 检查图书是否上架
                Book book = bookMapper.selectById(bookId);
                if (book == null || book.getStatus() != 1) {
                    continue;
                }
                
                // 计算加权分数
                double score = similarity * rating;
                
                // 累加分数
                bookScores.merge(bookId, score, Double::sum);
            }
        }
        
        // 获取用户借阅和收藏记录，增加权重
        enhanceScoresWithBorrowAndCollection(userId, bookScores, interactedBookIds);
        
        // 构建推荐DTO
        return buildRecommendationDTOs(bookScores, limit, RecommendationType.USER_CF.getValue());
    }
    
    /**
     * 根据借阅和收藏记录增强推荐分数
     */
    private void enhanceScoresWithBorrowAndCollection(Long userId, Map<Long, Double> bookScores, Set<Long> interactedBookIds) {
        // 获取用户借阅和收藏的图书对应的分类ID
        Set<Long> borrowedCategories = new HashSet<>();
        Set<Long> collectedCategories = new HashSet<>();
        
        // 查询用户借阅记录
        List<BorrowRecord> borrowRecords = borrowRecordMapper.selectList(
            new LambdaQueryWrapper<BorrowRecord>()
                .eq(BorrowRecord::getUserId, userId)
        );
        
        // 查询用户收藏记录
        List<Collection> collections = collectionMapper.selectList(
            new LambdaQueryWrapper<Collection>()
                .eq(Collection::getUserId, userId)
        );
        
        // 获取这些图书的信息
        Set<Long> bookIds = new HashSet<>();
        bookIds.addAll(borrowRecords.stream().map(BorrowRecord::getBookId).collect(Collectors.toSet()));
        bookIds.addAll(collections.stream().map(Collection::getBookId).collect(Collectors.toSet()));
        
        if (!bookIds.isEmpty()) {
            List<Book> books = bookMapper.selectList(
                new LambdaQueryWrapper<Book>()
                    .in(Book::getId, bookIds)
            );
            
            Map<Long, Book> bookMap = books.stream()
                    .collect(Collectors.toMap(Book::getId, book -> book));
            
            // 获取借阅图书的分类
            for (BorrowRecord record : borrowRecords) {
                Book book = bookMap.get(record.getBookId());
                if (book != null && book.getCategoryId() != null) {
                    borrowedCategories.add(book.getCategoryId());
                }
            }
            
            // 获取收藏图书的分类
            for (Collection collection : collections) {
                Book book = bookMap.get(collection.getBookId());
                if (book != null && book.getCategoryId() != null) {
                    collectedCategories.add(book.getCategoryId());
                }
            }
        }
        
        // 如果没有分类信息，直接返回
        if (borrowedCategories.isEmpty() && collectedCategories.isEmpty()) {
            return;
        }
        
        // 获取所有候选图书
        List<Book> candidateBooks = bookMapper.selectList(
            new LambdaQueryWrapper<Book>()
                .in(bookScores.isEmpty() ? false : true, Book::getId, bookScores.keySet())
        );
        
        // 增强分数
        for (Book book : candidateBooks) {
            Long bookId = book.getId();
            
            // 跳过用户已交互过的图书
            if (interactedBookIds.contains(bookId)) {
                continue;
            }
            
            if (book.getCategoryId() != null) {
                // 如果图书的分类在用户借阅过的分类中，增加分数
                if (borrowedCategories.contains(book.getCategoryId())) {
                    bookScores.merge(bookId, 1.2, (oldVal, newVal) -> oldVal * newVal);
                }
                
                // 如果图书的分类在用户收藏过的分类中，增加分数
                if (collectedCategories.contains(book.getCategoryId())) {
                    bookScores.merge(bookId, 1.1, (oldVal, newVal) -> oldVal * newVal);
                }
            }
        }
    }
    
    /**
     * 计算图书相似度（基于物品协同过滤）
     */
    private Map<Long, Map<Long, Double>> calculateBookSimilarities() {
        // 获取所有评分数据
        List<Rating> allRatings = ratingMapper.selectList(null);
        
        // 构建图书-用户-评分的映射
        Map<Long, Map<Long, Integer>> bookRatings = new HashMap<>();
        
        // 获取所有上架图书的ID
        List<Book> activeBooks = bookMapper.selectList(
            new LambdaQueryWrapper<Book>()
                .eq(Book::getStatus, 1)
                .select(Book::getId)
        );
        Set<Long> activeBookIds = activeBooks.stream()
                .map(Book::getId)
                .collect(Collectors.toSet());
        
        // 只处理上架图书的评分
        for (Rating rating : allRatings) {
            if (activeBookIds.contains(rating.getBookId())) {
                bookRatings.computeIfAbsent(rating.getBookId(), k -> new HashMap<>())
                        .put(rating.getUserId(), rating.getScore());
            }
        }
        
        // 计算图书之间的相似度
        Map<Long, Map<Long, Double>> bookSimilarities = new HashMap<>();
        
        List<Long> bookIds = new ArrayList<>(bookRatings.keySet());
        
        for (int i = 0; i < bookIds.size(); i++) {
            Long bookId1 = bookIds.get(i);
            Map<Long, Integer> ratings1 = bookRatings.get(bookId1);
            
            for (int j = i + 1; j < bookIds.size(); j++) {
                Long bookId2 = bookIds.get(j);
                Map<Long, Integer> ratings2 = bookRatings.get(bookId2);
                
                // 找出共同评分的用户
                Set<Long> commonUsers = new HashSet<>(ratings1.keySet());
                commonUsers.retainAll(ratings2.keySet());
                
                if (commonUsers.isEmpty()) {
                    continue;
                }
                
                // 计算余弦相似度
                double dotProduct = 0.0;
                double norm1 = 0.0;
                double norm2 = 0.0;
                
                for (Long userId : commonUsers) {
                    int rating1 = ratings1.get(userId);
                    int rating2 = ratings2.get(userId);
                    
                    dotProduct += rating1 * rating2;
                    norm1 += Math.pow(rating1, 2);
                    norm2 += Math.pow(rating2, 2);
                }
                
                double similarity = 0.0;
                if (norm1 > 0 && norm2 > 0) {
                    similarity = dotProduct / (Math.sqrt(norm1) * Math.sqrt(norm2));
                }
                
                // 只保存相似度大于0的记录
                if (similarity > 0) {
                    // 添加双向相似度
                    bookSimilarities.computeIfAbsent(bookId1, k -> new HashMap<>())
                            .put(bookId2, similarity);
                    bookSimilarities.computeIfAbsent(bookId2, k -> new HashMap<>())
                            .put(bookId1, similarity);
                }
            }
        }
        
        return bookSimilarities;
    }
    
    /**
     * 获取基于物品协同过滤的推荐
     */
    public List<RecommendationDTO> getItemCFRecommendations(Long userId, Integer limit) {
        // 检查用户是否存在
        checkUserExists(userId);
        
        // 获取用户已交互的图书
        Set<Long> interactedBookIds = getUserInteractedBookIds(userId);
        
        // 如果用户没有交互记录，返回空列表
        if (interactedBookIds.isEmpty()) {
            return Collections.emptyList();
        }
        
        // 计算图书相似度
        Map<Long, Map<Long, Double>> bookSimilarities = calculateBookSimilarities();
        
        // 查询用户的评分、借阅和收藏记录
        List<Rating> ratings = ratingMapper.selectList(
            new LambdaQueryWrapper<Rating>()
                .eq(Rating::getUserId, userId)
        );
        
        List<BorrowRecord> borrows = borrowRecordMapper.selectList(
            new LambdaQueryWrapper<BorrowRecord>()
                .eq(BorrowRecord::getUserId, userId)
        );
        
        List<Collection> collections = collectionMapper.selectList(
            new LambdaQueryWrapper<Collection>()
                .eq(Collection::getUserId, userId)
        );
        
        // 合并用户的所有交互图书
        Map<Long, Double> userBookInteractions = new HashMap<>();
        
        // 评分权重最高
        for (Rating rating : ratings) {
            userBookInteractions.put(rating.getBookId(), rating.getScore() * 0.6);
        }
        
        // 借阅权重其次
        for (BorrowRecord borrow : borrows) {
            userBookInteractions.merge(borrow.getBookId(), 4.0 * 0.3, Double::sum);
        }
        
        // 收藏权重最低
        for (Collection collection : collections) {
            userBookInteractions.merge(collection.getBookId(), 4.0 * 0.2, Double::sum);
        }
        
        // 计算推荐分数
        Map<Long, Double> bookScores = new HashMap<>();
        
        for (Map.Entry<Long, Double> entry : userBookInteractions.entrySet()) {
            Long bookId = entry.getKey();
            Double interaction = entry.getValue();
            
            // 获取相似图书
            Map<Long, Double> similarities = bookSimilarities.getOrDefault(bookId, Collections.emptyMap());
            
            // 计算推荐分数
            for (Map.Entry<Long, Double> simEntry : similarities.entrySet()) {
                Long similarBookId = simEntry.getKey();
                Double similarity = simEntry.getValue();
                
                // 跳过用户已交互过的图书
                if (interactedBookIds.contains(similarBookId)) {
                    continue;
                }
                
                // 检查图书是否上架
                Book book = bookMapper.selectById(similarBookId);
                if (book == null || book.getStatus() != 1) {
                    continue;
                }
                
                // 计算加权分数
                double score = interaction * similarity;
                
                // 累加分数
                bookScores.merge(similarBookId, score, Double::sum);
            }
        }
        
        // 构建推荐DTO
        return buildRecommendationDTOs(bookScores, limit, RecommendationType.ITEM_CF.getValue());
    }
    
    /**
     * 获取热门图书推荐
     */
    private List<RecommendationDTO> getHotBookRecommendations(Long userId, Set<Long> excludeBookIds, int limit) {
        // 获取热门图书（借阅次数最多的）
        List<Book> hotBooks = bookMapper.selectList(
            new LambdaQueryWrapper<Book>()
                .eq(Book::getStatus, 1)
                .notIn(excludeBookIds.isEmpty() ? false : true, Book::getId, excludeBookIds)
                .orderByDesc(Book::getBorrowedCount, Book::getAvgScore)
                .last("LIMIT " + Math.max(limit * 2, 20)) // 多查一些，以防部分图书已在排除列表中
        );
        
        // 转换为DTO
        List<RecommendationDTO> recommendations = new ArrayList<>();
        
        for (int i = 0; i < hotBooks.size() && recommendations.size() < limit; i++) {
            Book book = hotBooks.get(i);
            
            RecommendationDTO dto = new RecommendationDTO();
            dto.setBookId(book.getId());
            dto.setTitle(book.getTitle());
            dto.setAuthor(book.getAuthor());
            dto.setCoverUrl(book.getCoverUrl());
            dto.setAvgScore(book.getAvgScore());
            
            // 计算推荐分数，基于借阅次数和排名
            double score = (book.getBorrowedCount() == null ? 0 : book.getBorrowedCount()) * (1.0 - (double) i / hotBooks.size());
            dto.setRecommendationScore(new BigDecimal(score).setScale(4, RoundingMode.HALF_UP));
            
            dto.setRecommendationType(RecommendationType.HOT.getValue());
            dto.setRecommendationTypeDesc("热门推荐");
            
            recommendations.add(dto);
        }
        
        return recommendations;
    }
    
    /**
     * 获取新书推荐
     */
    private List<RecommendationDTO> getNewBookRecommendations(Long userId, Set<Long> excludeBookIds, int limit) {
        // 获取新上架的图书
        List<Book> newBooks = bookMapper.selectList(
            new LambdaQueryWrapper<Book>()
                .eq(Book::getStatus, 1)
                .notIn(excludeBookIds.isEmpty() ? false : true, Book::getId, excludeBookIds)
                .orderByDesc(Book::getCreateTime)
                .last("LIMIT " + Math.max(limit * 2, 20)) // 多查一些，以防部分图书已在排除列表中
        );
        
        // 转换为DTO
        List<RecommendationDTO> recommendations = new ArrayList<>();
        
        for (int i = 0; i < newBooks.size() && recommendations.size() < limit; i++) {
            Book book = newBooks.get(i);
            
            RecommendationDTO dto = new RecommendationDTO();
            dto.setBookId(book.getId());
            dto.setTitle(book.getTitle());
            dto.setAuthor(book.getAuthor());
            dto.setCoverUrl(book.getCoverUrl());
            dto.setAvgScore(book.getAvgScore());
            
            // 计算推荐分数，基于创建时间的新鲜度
            double score = 1.0 - (double) i / newBooks.size();
            dto.setRecommendationScore(new BigDecimal(score).setScale(4, RoundingMode.HALF_UP));
            
            dto.setRecommendationType(RecommendationType.NEW.getValue());
            dto.setRecommendationTypeDesc("新书推荐");
            
            recommendations.add(dto);
        }
        
        return recommendations;
    }
    
    /**
     * 获取基于内容的图书推荐
     * 基于用户历史交互图书的分类、出版社、作者等特征
     */
    public List<RecommendationDTO> getContentBasedRecommendations(Long userId, Integer limit) {
        // 检查用户是否存在
        checkUserExists(userId);
        
        // 获取用户已交互的图书ID
        Set<Long> interactedBookIds = getUserInteractedBookIds(userId);
        
        // 如果用户没有交互记录，返回空列表
        if (interactedBookIds.isEmpty()) {
            return Collections.emptyList();
        }
        
        // 获取用户交互过的图书的详细信息
        List<Book> interactedBooks = bookMapper.selectList(
            new LambdaQueryWrapper<Book>()
                .in(Book::getId, interactedBookIds)
        );
        
        // 统计作者、分类和出版社的偏好
        Map<String, Integer> authorPreferences = new HashMap<>();
        Map<Long, Integer> categoryPreferences = new HashMap<>();
        Map<String, Integer> publisherPreferences = new HashMap<>();
        
        // 获取用户评分数据以加权偏好
        Map<Long, Integer> userRatings = new HashMap<>();
        List<Rating> ratings = ratingMapper.selectList(
            new LambdaQueryWrapper<Rating>()
                .eq(Rating::getUserId, userId)
        );
        for (Rating rating : ratings) {
            userRatings.put(rating.getBookId(), rating.getScore());
        }
        
        // 查询用户借阅记录，根据借阅次数加权
        Map<Long, Integer> borrowCounts = new HashMap<>();
        List<BorrowRecord> borrows = borrowRecordMapper.selectList(
            new LambdaQueryWrapper<BorrowRecord>()
                .eq(BorrowRecord::getUserId, userId)
        );
        for (BorrowRecord borrow : borrows) {
            borrowCounts.merge(borrow.getBookId(), 1, Integer::sum);
        }
        
        // 计算用户对各特征的偏好
        for (Book book : interactedBooks) {
            // 基础权重
            int weight = 1;
            
            // 评分加权
            if (userRatings.containsKey(book.getId())) {
                weight = userRatings.get(book.getId());
            }
            
            // 借阅次数加权
            if (borrowCounts.containsKey(book.getId())) {
                weight += borrowCounts.get(book.getId());
            }
            
            // 累加作者偏好
            if (book.getAuthor() != null) {
                authorPreferences.merge(book.getAuthor(), weight, Integer::sum);
            }
            
            // 累加分类偏好
            if (book.getCategoryId() != null) {
                categoryPreferences.merge(book.getCategoryId(), weight, Integer::sum);
            }
            
            // 累加出版社偏好
            if (book.getPublisher() != null) {
                publisherPreferences.merge(book.getPublisher(), weight, Integer::sum);
            }
        }
        
        // 根据权重排序获取前3个作者、分类和出版社
        List<String> topAuthors = authorPreferences.entrySet().stream()
                .sorted(Map.Entry.<String, Integer>comparingByValue().reversed())
                .limit(3)
                .map(Map.Entry::getKey)
                .collect(Collectors.toList());
        
        List<Long> topCategories = categoryPreferences.entrySet().stream()
                .sorted(Map.Entry.<Long, Integer>comparingByValue().reversed())
                .limit(3)
                .map(Map.Entry::getKey)
                .collect(Collectors.toList());
        
        List<String> topPublishers = publisherPreferences.entrySet().stream()
                .sorted(Map.Entry.<String, Integer>comparingByValue().reversed())
                .limit(3)
                .map(Map.Entry::getKey)
                .collect(Collectors.toList());
        
        // 查询候选图书
        LambdaQueryWrapper<Book> queryWrapper = new LambdaQueryWrapper<Book>()
                .eq(Book::getStatus, 1) // 仅上架的图书
                .notIn(interactedBookIds.isEmpty() ? false : true, Book::getId, interactedBookIds);
        
        // 按照用户偏好筛选图书
        boolean hasCondition = false;
        
        if (!topAuthors.isEmpty()) {
            queryWrapper.or(w -> {
                for (String author : topAuthors) {
                    w.or().like(Book::getAuthor, author);
                }
            });
            hasCondition = true;
        }
        
        if (!topCategories.isEmpty()) {
            queryWrapper.or(w -> {
                for (Long categoryId : topCategories) {
                    w.or().eq(Book::getCategoryId, categoryId);
                }
            });
            hasCondition = true;
        }
        
        if (!topPublishers.isEmpty()) {
            queryWrapper.or(w -> {
                for (String publisher : topPublishers) {
                    w.or().like(Book::getPublisher, publisher);
                }
            });
            hasCondition = true;
        }
        
        // 如果没有偏好条件，直接返回空列表
        if (!hasCondition) {
            return Collections.emptyList();
        }
        
        // 查询符合条件的图书
        List<Book> candidateBooks = bookMapper.selectList(queryWrapper);
        
        // 计算推荐分数
        Map<Long, Double> bookScores = new HashMap<>();
        
        for (Book book : candidateBooks) {
            double score = 0.0;
            
            // 根据作者匹配加分
            if (book.getAuthor() != null) {
                for (String author : topAuthors) {
                    if (book.getAuthor().contains(author)) {
                        score += authorPreferences.getOrDefault(author, 0) * 0.4;
                        break;
                    }
                }
            }
            
            // 根据分类匹配加分
            if (book.getCategoryId() != null) {
                if (topCategories.contains(book.getCategoryId())) {
                    score += categoryPreferences.getOrDefault(book.getCategoryId(), 0) * 0.4;
                }
            }
            
            // 根据出版社匹配加分
            if (book.getPublisher() != null) {
                for (String publisher : topPublishers) {
                    if (book.getPublisher().contains(publisher)) {
                        score += publisherPreferences.getOrDefault(publisher, 0) * 0.2;
                        break;
                    }
                }
            }
            
            // 加上平均评分作为权重
            if (book.getAvgScore() != null) {
                score *= (book.getAvgScore().doubleValue() / 5.0 + 0.5);
            }
            
            // 保存分数
            if (score > 0) {
                bookScores.put(book.getId(), score);
            }
        }
        
        // 构建推荐DTO
        return buildRecommendationDTOs(bookScores, limit, RecommendationType.CONTENT_BASED.getValue());
    }
    
    /**
     * 获取热门图书推荐
     */
    public List<RecommendationDTO> getHotRecommendations(Long userId, Integer limit) {
        // 获取用户已交互的图书ID（如果userId不为空）
        Set<Long> excludeBookIds = new HashSet<>();
        if (userId != null) {
            excludeBookIds = getUserInteractedBookIds(userId);
        }
        
        // 获取热门图书（借阅次数最多的）
        List<Book> hotBooks = bookMapper.selectList(
            new LambdaQueryWrapper<Book>()
                .eq(Book::getStatus, 1)
                .notIn(excludeBookIds.isEmpty() ? false : true, Book::getId, excludeBookIds)
                .orderByDesc(Book::getBorrowedCount, Book::getAvgScore)
                .last("LIMIT " + Math.max(limit * 2, 20)) // 多查一些，以防部分图书已在排除列表中
        );
        
        // 计算推荐分数
        Map<Long, Double> bookScores = new HashMap<>();
        
        for (int i = 0; i < hotBooks.size(); i++) {
            Book book = hotBooks.get(i);
            
            // 计算分数，基于借阅次数和排名
            double score = (book.getBorrowedCount() == null ? 0 : book.getBorrowedCount()) * (1.0 - (double) i / hotBooks.size());
            
            bookScores.put(book.getId(), score);
        }
        
        // 构建推荐DTO
        return buildRecommendationDTOs(bookScores, limit, RecommendationType.HOT.getValue());
    }
    
    /**
     * 获取新书推荐
     */
    public List<RecommendationDTO> getNewRecommendations(Long userId, Integer limit) {
        // 获取用户已交互的图书ID（如果userId不为空）
        Set<Long> excludeBookIds = new HashSet<>();
        if (userId != null) {
            excludeBookIds = getUserInteractedBookIds(userId);
        }
        
        // 获取新上架的图书
        List<Book> newBooks = bookMapper.selectList(
            new LambdaQueryWrapper<Book>()
                .eq(Book::getStatus, 1)
                .notIn(excludeBookIds.isEmpty() ? false : true, Book::getId, excludeBookIds)
                .orderByDesc(Book::getCreateTime)
                .last("LIMIT " + Math.max(limit * 2, 20)) // 多查一些，以防部分图书已在排除列表中
        );
        
        // 计算推荐分数
        Map<Long, Double> bookScores = new HashMap<>();
        
        for (int i = 0; i < newBooks.size(); i++) {
            Book book = newBooks.get(i);
            
            // 计算分数，基于创建时间的新鲜度
            double score = 1.0 - (double) i / newBooks.size();
            
            bookScores.put(book.getId(), score);
        }
        
        // 构建推荐DTO
        return buildRecommendationDTOs(bookScores, limit, RecommendationType.NEW.getValue());
    }
    
    /**
     * 获取混合推荐
     * 整合用户协同过滤、物品协同过滤、基于内容、热门和新书等多种推荐结果
     */
    public List<RecommendationDTO> getHybridRecommendations(Long userId, Integer limit) {
        // 检查用户是否存在
        checkUserExists(userId);
        
        // 获取用户已交互的图书ID
        Set<Long> interactedBookIds = getUserInteractedBookIds(userId);
        
        List<RecommendationDTO> result = new ArrayList<>();
        
        // 如果用户有交互记录，使用协同过滤和基于内容的推荐
        if (!interactedBookIds.isEmpty()) {
            // 分配各算法的推荐数量
            int userCfLimit = (int) Math.ceil(limit * 0.3); // 30%用户协同过滤
            int itemCfLimit = (int) Math.ceil(limit * 0.25); // 25%物品协同过滤
            int contentBasedLimit = (int) Math.ceil(limit * 0.15); // 15%基于内容
            
            // 获取用户协同过滤推荐
            List<RecommendationDTO> userCfRecommendations = getUserCFRecommendations(userId, userCfLimit);
            result.addAll(userCfRecommendations);
            
            // 获取物品协同过滤推荐
            List<RecommendationDTO> itemCfRecommendations = getItemCFRecommendations(userId, itemCfLimit);
            result.addAll(itemCfRecommendations);
            
            // 获取基于内容的推荐
            List<RecommendationDTO> contentBasedRecommendations = getContentBasedRecommendations(userId, contentBasedLimit);
            result.addAll(contentBasedRecommendations);
        }
        
        // 补充热门推荐和新书推荐
        int remainingCount = limit - result.size();
        if (remainingCount > 0) {
            // 70%热门，30%新书
            int hotLimit = (int) Math.ceil(remainingCount * 0.7);
            int newLimit = remainingCount - hotLimit;
            
            // 获取热门推荐
            List<RecommendationDTO> hotRecommendations = getHotRecommendations(userId, hotLimit);
            result.addAll(hotRecommendations);
            
            // 获取新书推荐
            List<RecommendationDTO> newRecommendations = getNewRecommendations(userId, newLimit);
            result.addAll(newRecommendations);
        }
        
        // 如果仍不足，补充更多热门图书
        if (result.size() < limit) {
            // 获取已推荐的图书ID
            Set<Long> recommendedBookIds = result.stream()
                    .map(RecommendationDTO::getBookId)
                    .collect(Collectors.toSet());
            
            // 合并排除列表
            Set<Long> excludeBookIds = new HashSet<>(interactedBookIds);
            excludeBookIds.addAll(recommendedBookIds);
            
            // 查询更多热门图书
            List<Book> moreHotBooks = bookMapper.selectList(
                new LambdaQueryWrapper<Book>()
                    .eq(Book::getStatus, 1)
                    .notIn(excludeBookIds.isEmpty() ? false : true, Book::getId, excludeBookIds)
                    .orderByDesc(Book::getBorrowedCount, Book::getAvgScore)
                    .last("LIMIT " + (limit - result.size()))
            );
            
            // 转换为DTO
            for (int i = 0; i < moreHotBooks.size(); i++) {
                Book book = moreHotBooks.get(i);
                
                RecommendationDTO dto = new RecommendationDTO();
                dto.setBookId(book.getId());
                dto.setTitle(book.getTitle());
                dto.setAuthor(book.getAuthor());
                dto.setCoverUrl(book.getCoverUrl());
                dto.setAvgScore(book.getAvgScore());
                
                // 计算推荐分数，基于借阅次数和排名
                double score = (book.getBorrowedCount() == null ? 0 : book.getBorrowedCount()) * (1.0 - (double) i / moreHotBooks.size());
                dto.setRecommendationScore(new BigDecimal(score).setScale(4, RoundingMode.HALF_UP));
                
                dto.setRecommendationType(RecommendationType.HOT.getValue());
                dto.setRecommendationTypeDesc(RecommendationType.getDescByValue(RecommendationType.HOT.getValue()));
                
                result.add(dto);
            }
        }
        
        // 按推荐分数排序
        result.sort((a, b) -> b.getRecommendationScore().compareTo(a.getRecommendationScore()));
        
        // 限制返回数量
        return result.size() > limit ? result.subList(0, limit) : result;
    }
    
    /**
     * 获取与特定图书相似的图书推荐
     * 适用于图书详情页的相似图书推荐
     */
    public List<RecommendationDTO> getSimilarBookRecommendations(Long bookId, Long userId, Integer limit) {
        // 检查图书是否存在
        Book book = bookMapper.selectById(bookId);
        if (book == null) {
            throw new ServiceException("图书不存在");
        }
        
        // 获取用户已交互的图书ID（如果userId不为空）
        Set<Long> excludeBookIds = new HashSet<>();
        excludeBookIds.add(bookId); // 排除当前图书
        
        if (userId != null) {
            excludeBookIds.addAll(getUserInteractedBookIds(userId));
        }
        
        // 使用多种因素来查找相似图书
        Map<Long, Double> bookScores = new HashMap<>();
        
        // 1. 同类型图书 (40% 权重)
        if (book.getCategoryId() != null) {
            List<Book> sameCategories = bookMapper.selectList(
                new LambdaQueryWrapper<Book>()
                    .eq(Book::getStatus, 1)
                    .eq(Book::getCategoryId, book.getCategoryId())
                    .ne(Book::getId, bookId)
                    .notIn(excludeBookIds.size() > 1 ? true : false, Book::getId, excludeBookIds)
                    .orderByDesc(Book::getAvgScore)
                    .last("LIMIT 20")
            );
            
            for (int i = 0; i < sameCategories.size(); i++) {
                Book similarBook = sameCategories.get(i);
                double score = 0.4 * (1.0 - (double) i / sameCategories.size());
                if (similarBook.getAvgScore() != null) {
                    score *= (similarBook.getAvgScore().doubleValue() / 5.0 + 0.5); // 根据评分调整分数
                }
                bookScores.put(similarBook.getId(), score);
            }
        }
        
        // 2. 同作者图书 (30% 权重)
        if (book.getAuthor() != null) {
            List<Book> sameAuthor = bookMapper.selectList(
                new LambdaQueryWrapper<Book>()
                    .eq(Book::getStatus, 1)
                    .like(Book::getAuthor, book.getAuthor())
                    .ne(Book::getId, bookId)
                    .notIn(excludeBookIds.size() > 1 ? true : false, Book::getId, excludeBookIds)
                    .orderByDesc(Book::getAvgScore)
                    .last("LIMIT 10")
            );
            
            for (int i = 0; i < sameAuthor.size(); i++) {
                Book similarBook = sameAuthor.get(i);
                double score = 0.3 * (1.0 - (double) i / sameAuthor.size());
                if (similarBook.getAvgScore() != null) {
                    score *= (similarBook.getAvgScore().doubleValue() / 5.0 + 0.5);
                }
                // 累加分数
                bookScores.merge(similarBook.getId(), score, Double::sum);
            }
        }
        
        // 3. 同出版社图书 (15% 权重)
        if (book.getPublisher() != null) {
            List<Book> samePublisher = bookMapper.selectList(
                new LambdaQueryWrapper<Book>()
                    .eq(Book::getStatus, 1)
                    .like(Book::getPublisher, book.getPublisher())
                    .ne(Book::getId, bookId)
                    .notIn(excludeBookIds.size() > 1 ? true : false, Book::getId, excludeBookIds)
                    .orderByDesc(Book::getAvgScore)
                    .last("LIMIT 10")
            );
            
            for (int i = 0; i < samePublisher.size(); i++) {
                Book similarBook = samePublisher.get(i);
                double score = 0.15 * (1.0 - (double) i / samePublisher.size());
                if (similarBook.getAvgScore() != null) {
                    score *= (similarBook.getAvgScore().doubleValue() / 5.0 + 0.5);
                }
                // 累加分数
                bookScores.merge(similarBook.getId(), score, Double::sum);
            }
        }
        
        // 4. 使用协同过滤找到相似图书 (15% 权重)
        Map<Long, Map<Long, Double>> bookSimilarities = calculateBookSimilarities();
        Map<Long, Double> similarBooks = bookSimilarities.getOrDefault(bookId, new HashMap<>());
        
        for (Map.Entry<Long, Double> entry : similarBooks.entrySet()) {
            Long similarBookId = entry.getKey();
            Double similarity = entry.getValue();
            
            // 跳过已排除的图书
            if (excludeBookIds.contains(similarBookId)) {
                continue;
            }
            
            // 累加分数
            bookScores.merge(similarBookId, 0.15 * similarity, Double::sum);
        }
        
        // 如果相似图书数量不足，补充同类别热门图书
        if (bookScores.size() < limit && book.getCategoryId() != null) {
            // 获取已经有分数的图书ID
            Set<Long> scoredBookIds = new HashSet<>(bookScores.keySet());
            scoredBookIds.addAll(excludeBookIds);
            
            List<Book> popularBooks = bookMapper.selectList(
                new LambdaQueryWrapper<Book>()
                    .eq(Book::getStatus, 1)
                    .eq(Book::getCategoryId, book.getCategoryId())
                    .notIn(scoredBookIds.isEmpty() ? false : true, Book::getId, scoredBookIds)
                    .orderByDesc(Book::getBorrowedCount, Book::getAvgScore)
                    .last("LIMIT " + (limit - bookScores.size()))
            );
            
            for (int i = 0; i < popularBooks.size(); i++) {
                Book popularBook = popularBooks.get(i);
                double score = 0.1 * (1.0 - (double) i / popularBooks.size());
                if (popularBook.getAvgScore() != null) {
                    score *= (popularBook.getAvgScore().doubleValue() / 5.0 + 0.5);
                }
                bookScores.put(popularBook.getId(), score);
            }
        }
        
        // 额外添加一个特殊类型，表示这是相似图书推荐
        class SimilarBookRecommendationType {
            public static final int VALUE = 6;
            public static final String DESC = "相似图书";
        }
        
        // 构建推荐DTO列表
        return buildRecommendationDTOs(bookScores, limit, SimilarBookRecommendationType.VALUE)
                .stream()
                .peek(dto -> dto.setRecommendationTypeDesc(SimilarBookRecommendationType.DESC))
                .collect(Collectors.toList());
    }
} 